package com.billlv.codegenerator.common.filter;

import com.billlv.codegenerator.common.utils.JwtUtils;
import com.billlv.codegenerator.domain.vo.UsersVO;
import com.billlv.codegenerator.service.BlacklistService;
import com.billlv.codegenerator.service.UsersService;
import com.billlv.codegenerator.service.impl.UserDetailsServiceImpl;
import io.jsonwebtoken.ExpiredJwtException;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

@Component
@Slf4j
public class JwtRequestFilter extends OncePerRequestFilter {

    @Autowired
    private UserDetailsServiceImpl userDetailsService;
    @Autowired
    private UsersService userService;

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private BlacklistService blacklistService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {

        String path = request.getServletPath();
        if (isExcludedPath(path)) {
            chain.doFilter(request, response);
            return;
        }
        String token = extractTokenFromHeader(request);
        if (token == null) {

            respondWithError(response, HttpServletResponse.SC_UNAUTHORIZED, "Missing or invalid JWT Token in Cookie");
            return;
        }
        try {
            String userId = jwtUtils.getUserIdFromToken(token);
            String tokenId = jwtUtils.getTokenId(token);
            // 检查黑名单
            if (blacklistService.isBlacklisted(tokenId)) {
                logger.warn("JWT Token is blacklisted: " + tokenId);
                respondWithError(response, HttpServletResponse.SC_UNAUTHORIZED, "JWT Token is blacklisted");
                return;
            }

            if (userId != null && SecurityContextHolder.getContext().getAuthentication()==null) {
                authenticateUser(userId, token, request);
            }

        } catch (ExpiredJwtException e) {
            logger.warn("JWT Token has expired");
            handleExpiredToken(request, response, chain);
            return;
        } catch (IllegalArgumentException e) {
            logger.error("Unable to get JWT Token", e);
            respondWithError(response, HttpServletResponse.SC_UNAUTHORIZED, "Invalid JWT Token");
            return;
        } catch (Exception e) {
            logger.error("Unexpected error during token validation", e);
            respondWithError(response, HttpServletResponse.SC_UNAUTHORIZED, "Unexpected error");
            return;
        }

        chain.doFilter(request, response);
    }

    /**
     * 检查是否是无需验证的路径
     */
    private boolean isExcludedPath(String path) {
        return "/actuator/health".equals(path)||"/api/auth/login".equals(path)||"/api/register".equals(path)|| "/api/auth/refresh-token".equals(path);
    }

    /**
     * 从请求头中提取 JWT Token（用于微信小程序）
     */
    private String extractTokenFromHeader(HttpServletRequest request) {
        // 检查自定义的 Authorization 头
        String authorizationHeader = request.getHeader("Authorization");
        if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
            return authorizationHeader.substring(7); // 去掉 "Bearer " 前缀
        }
        return null;
    }


    /**
     * 处理过期 Token
     */
    /**
     * 处理过期 Token
     */
    private void handleExpiredToken(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws IOException {
        respondWithError(response, HttpServletResponse.SC_UNAUTHORIZED, "Refresh Token is invalid or missing");

    }

    /**
     * 执行用户认证（仅基于 userId）
     */
    private void authenticateUser(String userId, String token, HttpServletRequest request) {
        // 验证 Token 的合法性
        if (jwtUtils.validateJwtToken(token)) {
            // 从数据库或缓存加载用户信息
            UsersVO usersVO = userService.read(Long.parseLong(userId));
            UserDetails userDetails = userDetailsService.loadUserByUsername(usersVO.getUsername());
            // 构建认证对象
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                    userDetails, null, userDetails.getAuthorities());
            authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

            // 将认证信息存入 SecurityContext
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }
    }



    /**
     * 返回错误响应
     */
    private void respondWithError(HttpServletResponse response, int status, String message) throws IOException {
        response.setStatus(status);
        response.setContentType("application/json");
        response.getWriter().write("{\"error\": \"" + message + "\"}");
    }
}
